﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using MyPhotoIndex.Utilities;
using System.Globalization;
using MyPhotoIndex.Controls.AutoCompleteToolstripTextBox;

namespace MyPhotoIndex.Controls
{
    public partial class AutoCompleteTextBox : TextBox
    {
        private static Brush ms_clearBrush;
        private static Image ms_editIcon = Resources.Resources.EditOptions;

        private Form m_listForm = new Form();
        private ListBox m_valueList = new ListBox();
        private AutoCompleteStringCollection m_values;
        private string m_currentValue;
        private Brush m_selectedBrush = new SolidBrush(Color.FromArgb(124, 212, 124));
        private bool m_listvalueSelected;

        private Form m_helperForm = new  HelperForm();
        private MonthCalendar m_datePickerFrom = new MonthCalendar();
        private MonthCalendar m_datePickerTo = new MonthCalendar();
        private Button m_helperButton = new Button();

        private bool skipSetCursor;

        public bool ListValueSelected
        {
            get { return m_listvalueSelected; }
        }

        public DateTime StartDate
        {
            get { return m_datePickerFrom.SelectionStart; }
            set 
            {
                m_datePickerFrom.MinDate = value;
                m_datePickerTo.MinDate = value; 
            }
        }

        public DateTime EndDate
        {
            get { return m_datePickerFrom.SelectionEnd; }
            set
            {
                m_datePickerFrom.MaxDate = value;
                m_datePickerTo.MaxDate = value;
            }
        }

        public DateTime[] MarkedDates
        {
            get { return m_datePickerFrom.BoldedDates; }
            set
            {
                m_datePickerFrom.BoldedDates = value;
                m_datePickerTo.BoldedDates = value;
            }

        }

        public AutoCompleteTextBox()
        {
            ms_clearBrush = new SolidBrush(base.BackColor);

            m_values = base.AutoCompleteCustomSource;

            m_listForm.FormBorderStyle = FormBorderStyle.None;
            m_listForm.ShowInTaskbar = false;
            m_listForm.ShowIcon = false;
            m_listForm.SizeGripStyle = SizeGripStyle.Show;
            m_listForm.BackColor = Color.White;

            m_valueList.BorderStyle = BorderStyle.FixedSingle;
            m_valueList.Dock = DockStyle.Fill;
            m_valueList.DrawMode = DrawMode.OwnerDrawFixed;
            m_valueList.DrawItem += new DrawItemEventHandler(m_valueList_DrawItem);
            m_valueList.GotFocus += new EventHandler(m_valueList_GotFocus);
            m_valueList.Click += new EventHandler(m_valueList_Click);
            m_listForm.Controls.Add(m_valueList);

            base.KeyUp += new KeyEventHandler(AutoCompleteTextBox_KeyUp);
            base.LostFocus += new EventHandler(AutoCompleteTextBox_LostFocus);
            base.Leave += new EventHandler(AutoCompleteTextBox_Leave);
            base.SizeChanged += new EventHandler(AutoCompleteTextBox_SizeChanged);
            base.LocationChanged += new EventHandler(AutoCompleteTextBox_LocationChanged);

            base.Margin = new Padding(base.Margin.Left, base.Margin.Top, base.Margin.Right + 20, base.Margin.Bottom);
            m_helperForm.FormBorderStyle = FormBorderStyle.None;
            m_helperForm.ShowInTaskbar = false;
            m_helperForm.ShowIcon = false;
            m_helperForm.BackColor = Color.White;

            m_datePickerFrom.Left = 4;
            m_datePickerFrom.Height = 180;
            m_datePickerFrom.DateSelected += new DateRangeEventHandler(m_datePicker_DateSelected);
            m_helperForm.Controls.Add(m_datePickerFrom);

            m_datePickerTo.Left = m_helperForm.Width - m_datePickerTo.Width - 4;
            m_datePickerTo.Height = 180;
            m_datePickerTo.DateSelected += new DateRangeEventHandler(m_datePicker_DateSelected);
            m_helperForm.Controls.Add(m_datePickerTo);

            m_helperButton.Text = "Ok";
            m_helperButton.BackColor = SystemColors.Control;
            m_helperButton.Click += new EventHandler(m_helperButton_Click);

            m_helperForm.Controls.Add(m_helperButton);

            m_helperForm.Visible = true;
            m_helperForm.Visible = false;
        }

        void m_helperButton_Click(object sender, EventArgs e)
        {
            HideHelperForm();

            string fromDate = m_datePickerFrom.SelectionStart.ToString("d", System.Threading.Thread.CurrentThread.CurrentUICulture);
            string toDate = m_datePickerTo.SelectionStart.ToString("d", System.Threading.Thread.CurrentThread.CurrentUICulture);

            if (m_datePickerFrom.SelectionStart.CompareTo(m_datePickerTo.SelectionStart) == 0)
            {
                base.Text = fromDate;
            }
            else
            {
                base.Text = fromDate + " - " + toDate;
            }

            m_listvalueSelected = true;
            base.OnKeyUp(new KeyEventArgs(Keys.Enter));
        }

        void m_datePicker_DateSelected(object sender, DateRangeEventArgs e)
        {
            if (m_datePickerFrom.SelectionStart.CompareTo(m_datePickerTo.SelectionStart) > 0 ||
                sender == m_datePickerFrom)
            {
                m_datePickerTo.SetDate(m_datePickerFrom.SelectionStart);
            }
        }

        void AutoCompleteTextBox_LocationChanged(object sender, EventArgs e)
        {
            SetHelperFormDims();
        }

        void AutoCompleteTextBox_SizeChanged(object sender, EventArgs e)
        {
            SetHelperFormDims();
        }

        void m_valueList_Click(object sender, EventArgs e)
        {
            base.Text = m_valueList.SelectedItem.ToString();
            this.Focus();
            base.OnKeyUp(new KeyEventArgs(Keys.Enter));

            HideAutoCompleteList();
        }

        void m_valueList_GotFocus(object sender, EventArgs e)
        {

        }

        void m_valueList_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.State == DrawItemState.Selected)
            {
                e.Graphics.FillRectangle(m_selectedBrush, e.Bounds);
            }
            else
            {
                e.Graphics.FillRectangle(Brushes.White, e.Bounds);
            }

            string itemValue = m_valueList.Items[e.Index].ToString();
            e.Graphics.DrawString(itemValue, m_valueList.Font, Brushes.Black, e.Bounds);
        }

        void AutoCompleteTextBox_Leave(object sender, EventArgs e)
        {
            if (m_listForm.ContainsFocus == false)
            {
                HideAutoCompleteList();
            }

            if (m_helperForm.ContainsFocus == false)
            {
                HideHelperForm();
            }
        }

        void AutoCompleteTextBox_LostFocus(object sender, EventArgs e)
        {
        }

        private void HideAutoCompleteList()
        {
            if (m_listForm.Visible == true)
            {
                m_listForm.Hide();
            }
        }

        void AutoCompleteTextBox_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape)
            {
                HideAutoCompleteList();
                HideHelperForm();
            }
            else
                if (e.KeyCode == Keys.Down)
                {
                    m_valueList.SelectedIndex = Math.Min(m_valueList.Items.Count - 1, m_valueList.SelectedIndex + 1);
                }
                else
                    if (e.KeyCode == Keys.Up)
                    {
                        m_valueList.SelectedIndex = Math.Max(0, m_valueList.SelectedIndex - 1);
                    }
                    else
                        if (e.KeyCode == Keys.Enter)
                        {
                            if (m_listForm.Visible == true)
                            {
                                HideAutoCompleteList();
                                base.Text = m_valueList.SelectedItem.ToString();
                                m_listvalueSelected = true;
                            }
                            else
                            {
                                EvaluateShowAutoComplete(base.Text);
                            }
                        }
                        else
                        {
                            EvaluateShowAutoComplete(base.Text);
                        }

            HideHelperForm();
        }

        private void ShowAutoCompleteList()
        {
            if (m_listForm.Visible == false)
            {
                Win32Interop.ShowWindow(m_listForm.Handle, Win32Interop.SW_SHOWNOACTIVATE);
                Win32Interop.SetWindowPos(m_listForm.Handle.ToInt32(), Win32Interop.HWND_TOPMOST,
                 m_listForm.Left, m_listForm.Top, m_listForm.Width, m_listForm.Height,
                 Win32Interop.SWP_NOACTIVATE);

                m_listForm.Width = 200;
                m_listForm.Height = 200;
                m_listvalueSelected = false;
            }
        }

        private void EvaluateShowAutoComplete(string value)
        {
            m_valueList.Items.Clear();

            if (string.IsNullOrEmpty(value.Trim()) == false)
            {
                foreach (string match in m_values)
                {
                    if (match.Contains(value) == true)
                    {
                        m_valueList.Items.Add(match);
                    }
                }
            }

            if (m_valueList.Items.Count > 0)
            {
                m_valueList.SelectedIndex = 0;
                ShowAutoCompleteList();
                m_currentValue = value;
            }
            else
            {
                HideAutoCompleteList();
            }

            Rectangle rect = this.Parent.RectangleToScreen(this.Bounds);
            m_listForm.Top = rect.Bottom;
            m_listForm.Left = rect.Left;
        }

        protected override void WndProc(ref Message m)
        {
            int helperIconWidth = 13;
            int helperIconHeight = 13;

            int adjustment = this.BorderStyle == BorderStyle.FixedSingle ? 2 : 0;

            if (m.Msg == Win32Interop.WM_NCHITTEST)
            {
                Point p = PointToClient(new Point((int)m.LParam));
                int x = p.X;
                int y = p.Y;

                Point location = new Point(base.Width - (helperIconWidth + adjustment + 2), (base.Height - helperIconHeight) / 2);
                Rectangle iconRect = new Rectangle(location, new Size(helperIconWidth, helperIconHeight));

                if (iconRect.Contains(p) == true)
                {
                   Cursor.Current  = Cursors.Hand;
                   skipSetCursor = true;

                   if (MouseButtons == MouseButtons.Left)
                   {
                       ShowHelperForm();
                   }
                }
            }
            else
                if (m.Msg == Win32Interop.WM_NCCALCSIZE)
                {

                    if ((int)m.WParam == 0)     // False
                    {

                        Win32Interop.RECT rect = (Win32Interop.RECT)Marshal.PtrToStructure(m.LParam, typeof(Win32Interop.RECT));
                        rect.right -= helperIconWidth - adjustment;

                        Marshal.StructureToPtr(rect, m.LParam, false);

                        m.Result = IntPtr.Zero;
                    }
                    else if ((int)m.WParam == 1) // True
                    {

                        Win32Interop.NCCALCSIZE_PARAMS nccsp = (Win32Interop.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(m.LParam,
                                                        typeof(Win32Interop.NCCALCSIZE_PARAMS));

                        nccsp.rect0.right -= helperIconWidth - adjustment;
                        Marshal.StructureToPtr(nccsp, m.LParam, false);
                        m.Result = IntPtr.Zero;
                    }
                }
                else
                    if (m.Msg == Win32Interop.WM_NCPAINT)
                    {
                        IntPtr hDC = Win32Interop.GetWindowDC(m.HWnd);
                        if (hDC != IntPtr.Zero)
                        {
                            using (Graphics maing = Graphics.FromHdc(hDC))
                            {
                                Point location = new Point(base.Width - (helperIconWidth + adjustment + 2), (base.Height - helperIconHeight) / 2);
                                Rectangle iconRect = new Rectangle(location, new Size(helperIconWidth, base.Height));
                                maing.FillRectangle(ms_clearBrush, iconRect);
                                maing.DrawImage(ms_editIcon, location.X, location.Y, 13, 13);
                            }
                            Win32Interop.ReleaseDC(m.HWnd, hDC);
                        }
                        m.Result = IntPtr.Zero;
                    }
                    else
                    if (m.Msg == Win32Interop.WM_SETCURSOR &&
                        skipSetCursor == true)
                    {
                        skipSetCursor = false;
                        return;
                    }

            base.WndProc(ref m);
        }

        private void ShowHelperForm()
        {
            if (m_helperForm.Visible == false)
            {
                Rectangle rect = this.Parent.RectangleToScreen(this.Bounds);
                m_helperForm.Top = rect.Bottom;
                m_helperForm.Left = rect.Left;

                Win32Interop.ShowWindow(m_helperForm.Handle, Win32Interop.SW_SHOWNOACTIVATE);
                Win32Interop.SetWindowPos(m_helperForm.Handle.ToInt32(), Win32Interop.HWND_TOPMOST,
                 m_helperForm.Left, m_helperForm.Top, m_helperForm.Width, m_helperForm.Height,
                 Win32Interop.SWP_NOACTIVATE);

                base.Focus();
            }
        }

        private void HideHelperForm()
        {
            if (m_helperForm.Visible == true)
            {
                m_helperForm.Hide();
            }
        }

        private void SetHelperFormDims()
        {
            if (this.Parent == null)
            {
                return;
            }

            m_datePickerTo.Left = m_helperForm.Width - m_datePickerTo.Width - 4;
            m_datePickerTo.Top = 4;

            m_datePickerFrom.Top = 4;
            m_datePickerFrom.Left = 4;

            m_helperForm.Padding = new Padding();
            Rectangle rect = this.Parent.RectangleToScreen(this.Bounds);
            m_helperForm.Top = rect.Bottom;
            m_helperForm.Left = rect.Left;

            m_helperButton.Left = m_helperForm.Width - m_helperButton.Width - 5;
            m_helperButton.Top = m_helperForm.Height - m_helperButton.Height - 5 - m_helperButton.Padding.Bottom;
            m_helperForm.Width = m_datePickerFrom.Width + m_datePickerTo.Width + 30;
            m_helperForm.Height = 190;

            m_helperForm.Invalidate();
        }
    }
}
